package com.gitee.yannzh.rune.core.excel;

import cn.hutool.core.util.URLUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.ReadListener;
import org.dromara.core.trans.anno.Trans;
import org.dromara.core.trans.util.ReflectUtils;
import com.gitee.yannzh.rune.core.exception.SystemException;
import com.gitee.yannzh.rune.core.util.HttpContextUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;

/**
 * @author yann
 * @description: easy-excel工具类
 * @date 2022/2/25 12:03
 * @version：1.0
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExcelUtil {


    public static <T> void export(String excelName, String sheetName, Class<T> head, List<T> data) {
        try {
            HttpServletResponse response = HttpContextUtil.getHttpServletResponse();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easy excel没有关系
            String fileName = URLUtil.encode(excelName).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), head).sheet(StringUtils.isBlank(sheetName) ? "sheet1" : sheetName).doWrite(data);
        } catch (IOException e) {
            throw new SystemException(e);
        }
    }


    /**
     * 通过输出流导出excel
     *
     * @param outputStream 输出流
     * @param clazz        实体类型
     * @param data         数据
     * @param <T>          excel对应实体泛型
     */
    public static <T> void export(OutputStream outputStream, Class<T> clazz, List<T> data) {
        EasyExcel.write(outputStream, clazz)
                .sheet()
                .doWrite(data);
    }

    /**
     * 通过输出流导出excel
     *
     * @param outputStream 输出流
     * @param clazz        实体类型
     * @param supplier     数据提供者
     * @param <T>          excel对应实体泛型
     */
    public static <T> void export(OutputStream outputStream, Class<T> clazz, Supplier<Collection<?>> supplier) {
        EasyExcel.write(outputStream, clazz)
                .sheet()
                .doWrite(supplier);
    }


    /**
     * 通过文件保存路径导出excel
     *
     * @param path  保存excel完整路径
     * @param clazz 实体类型
     * @param data  数据
     * @param <T>   excel对应实体泛型
     */
    public static <T> void export(String path, Class<T> clazz, List<T> data) {
        EasyExcel.write(path, clazz)
                .sheet()
                .doWrite(data);
    }

    /**
     * 通过文件保存路径导出excel
     *
     * @param path     保存excel完整路径
     * @param clazz    实体类型
     * @param supplier 数据提供者
     * @param <T>      excel对应实体泛型
     */
    public static <T> void export(String path, Class<T> clazz, Supplier<Collection<?>> supplier) {
        EasyExcel.write(path, clazz)
                .sheet()
                .doWrite(supplier);
    }


    /**
     * 通过文件路径读取数据
     *
     * @param path  文件绝对路径
     * @param clazz 实体类型
     * @return
     */
    public static List<T> importExcelSync(String path, Class<T> clazz) {
        return EasyExcel.read(path).head(clazz).sheet().doReadSync();
    }

    /**
     * 通过输入流读取数据
     *
     * @param inputStream 输入流
     * @param clazz       实体类型
     * @return
     */
    public static List<T> importExcelSync(InputStream inputStream, Class<T> clazz) {
        return EasyExcel.read(inputStream).head(clazz).sheet().doReadSync();
    }


    /**
     * 通过文件路径读取数据，并自定义数据处理器
     *
     * @param path     文件绝对路径
     * @param clazz    实体类型
     * @param listener 自定义监听器
     * @return
     */
    public static <T> void importExcel(String path, Class<T> clazz, ReadListener<T> listener) {
        EasyExcel.read(path).head(clazz).registerReadListener(listener).sheet().doRead();
    }


    /**
     * 通过输入流读取数据，并自定义数据处理器
     *
     * @param inputStream 输入流
     * @param clazz       实体类型
     * @param listener    自定义监听器
     * @return
     */
    public static <T> void importExcel(InputStream inputStream, Class<T> clazz, ReadListener<T> listener) {
        EasyExcel.read(inputStream).head(clazz).registerReadListener(listener).sheet().doRead();
    }


    /**
     * 解析字典数据到字段上
     * 比如 T中有 genderLabel字段 为男 需要给 gender 字段自动设置为0
     *
     * @param dataList 需要被反向解析的数据
     */
//    @SneakyThrows
//    public static <T extends TransPojo> void parseDict(List<T> dataList) {
//        //没有数据就不需要初始化
//        if (CollectionUtil.isEmpty(dataList)) {
//            return;
//        }
//        Class<? extends TransPojo> clazz = dataList.get(0).getClass();
//        //拿到所有需要反向翻译的字段
//        List<Field> fields = ReflectUtils.getAnnotationField(clazz, Trans.class);
//        //过滤出字典翻译
//        fields = fields.stream().filter(field -> TransType.DICTIONARY.equals(field.getAnnotation(Trans.class).type())).collect(Collectors.toList());
//        DictionaryTransService dictionaryTransService = SpringUtil.getBean(DictionaryTransService.class);
//        for (T data : dataList) {
//            for (Field field : fields) {
//                Trans trans = field.getAnnotation(Trans.class);
//                // key不能为空并且ref不为空的才自动处理
//                if (StrUtil.isAllNotBlank(trans.key(), trans.ref())) {
//                    Field ref = ReflectUtils.getDeclaredField(clazz, trans.ref());
//                    ref.setAccessible(true);
//                    // 获取字典反向值
//                    String value = dictionaryTransService.getUnTransMap().get(trans.key() + "_" + ref.get(data));
//                    if (StringUtils.isBlank(value)) {
//                        continue;
//                    }
//                    // 一般目标字段是int或者string字段 后面有添加单独抽离方法
//                    if (Integer.class.equals(field.getType())) {
//                        field.setAccessible(true);
//                        field.set(data, ConverterUtils.toInteger(value));
//                    } else {
//                        field.setAccessible(true);
//                        field.set(data, ConverterUtils.toString(value));
//                    }
//                }
//            }
//        }
//
//    }

    /**
     * 是否需要手动翻译
     *
     * @param clazz
     * @return
     */
    public static boolean hasTrans(Class<?> clazz) {
        List<Field> fields = ReflectUtils.getAllField(clazz);
        Iterator var4 = fields.iterator();

        while (var4.hasNext()) {
            Field field = (Field) var4.next();
            if (field.getAnnotation(Trans.class) != null) {
                return true;
            }
        }
        return false;
    }
}
